home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Developer Essentials / MPW Interfaces & Libraries / AStructMacs / ProgStrucMacs.a < prev    next >
Encoding:
Text File  |  1992-01-29  |  52.6 KB  |  1,134 lines  |  [TEXT/MPS ]

  1.         PRINT    Push,NoObj
  2.         TITLE    'ProgStrucMacs - Program Structure Macro Statements'
  3.         
  4. *******************************************************************************
  5. *                                                                             *
  6. *                                ProgStrucMacs                                *
  7. *                                                                             *
  8. *                        Program Structure Statements                         *
  9. *                                                                             *
  10. *                                Ira L. Ruben                                 *
  11. *                                  09/15/86                                   *
  12. *                                                                             *
  13. *                  Copyright Apple Computer, Inc. 1986-1989                   *
  14. *                             All rights reserved.                            *
  15. *                                                                             *
  16. *       ---------------------------------------------------------------       *
  17. *                                                                             *
  18. * External macros in this set are:                                            *
  19. *                                                                             *
  20. *   • Procedure - Parse a procedure declaration                               *
  21. *   • Function  - Parse a function declaration                                *
  22. *   • Var       - Declare local variables on the stack                        *
  23. *   • Begin     - Procedure primary entry point                               *
  24. *   • Enter     - Procedure secondary entry point                             *
  25. *   • Return    - Procedure and function exit                                 *
  26. *   • Call      - procedure, function, or trap call                           *
  27. *                                                                             *
  28. * Internal macros in this set are:                                            *
  29. *                                                                             *
  30. *   • ScanArgs# - Parse a proc name and its argument list                     *
  31. *   • Dcl1Var#  - Process local variable declaration or formal param          *
  32. *                                                                             *
  33. * Thanks to Steve Brecher of Software Supply whose original set of macros     *
  34. * provided many ideas and syntax used here.                                   *
  35. *                                                                             *
  36. *******************************************************************************
  37.  
  38.  
  39.         TITLE    'ScanArgs# - Parse a proc name and its argument list'
  40.         
  41.         MACRO
  42.         ScanArgs#    &ArgList
  43. .*
  44. .******************************************************************************
  45. .* ScanArgs# - Parse a proc name and its argument list       (internal macro) *
  46. .*                                                                            *
  47. .* Input:  &ArgList = <modname> ['('arg1,...argN')'] [':'<result>]            *
  48. .*         &Areg = 'A' ==> we must have CALL.A (An)[(arglist...)]           *                                   *
  49. .*                                                                            *
  50. .* Output: &ModName#   = <modname>                                     (SETC) *
  51. .*         &NbrOfArgs# = number of arguments                           (SETA) *
  52. .*         &Args#      = array of arguments; &Args#[i] = i'th arg      (SETC) *
  53. .*         &FInfo#     = <result>                                      (SETC) *
  54. .******************************************************************************
  55. .*
  56.         GBLC        &ModName#            ; <modname>
  57.         GBLC        &FInfo#            ; <result>
  58.         GBLC        &Args#[50]        ; argument list
  59.         GBLA        &NbrOfArgs#        ; number of args in argument list
  60.         GBLC        &Areg            ; "A" ==> call (An)[(arglist...)] case
  61. .*
  62.         LCLC        &S,&F[2]
  63.         LCLA        &i,&j
  64. .*
  65.     &S: SETC &Trim(&ArgList)            ; Ignore leading/trailing blanks
  66.     &i: SETA &Pos('(', &S)            ; Find left-most "(", if any
  67.     IF &Areg = 'A' THEN                ; But if we are doing a CALL.A (An)...
  68.       &j:    SETA &Pos('(', &S[&i+1:255]); ...find 2nd "("
  69.       IF &j ≠ 0 THEN                ; If there is one, we got arg list
  70.         &i:    SETA &i + &j            ; Adjust to point at 2nd "("
  71.       ELSE                        ; If there isn't an arg list...
  72.         &i:    SETA 0                ; Set index accordingly
  73.       ENDIF
  74.     ENDIF
  75.     IF &i = 0 THEN                    ; If no args...
  76.       &NbrOfArgs#: SETA 0            ; ...say so!
  77.       &i:          SETA &List(&S, '&F', ':')
  78.       &ModName#:   SETC &Trim(&F[1])    ; Set &ModName# to stuff before any ":"
  79.       &FInfo#:     SETC    &Trim(&F[2])    ; &FInfo# is everything to right of ":"
  80.     ELSE                            ; If there are args, set up globals
  81.       &ModName#:   SETC &Trim(&ArgList[1:&i-1])
  82.       &NbrOfArgs#: SETA &List(&ArgList[&i+1:255], '&Args#')
  83.       &i:          SETA &List(&Args#[&NbrOfArgs#], '&F', ')')
  84.       &Args#[&NbrOfArgs#]: SETC &Trim(&F[1])
  85.       &FInfo#:      SETC &SubStr(&Trim(&F[2]), 2, 255)
  86.     ENDIF
  87. .*
  88. .*&i    seta    0
  89. .*    writeln
  90. .*    writeln    &ModName#
  91. .*    while &i < &NbrOfArgs# do
  92. .*      &i: seta &i+1
  93. .*      writeln &i, ': "', &Args#[&i], '"'
  94. .*    endw
  95. .*    writeln    '"', &FInfo#, '"'
  96. .*    print    pop
  97.         ENDM
  98.  
  99.  
  100.         TITLE    'Dcl1Var# - Process local variable decl. or formal param'
  101.         
  102.         MACRO
  103.         Dcl1Var#    &Opnd,&Align:A=0
  104. .*
  105. .******************************************************************************
  106. .* Dcl1Var# - Process local variable decl. or formal param   (internal macro) *
  107. .*                                                                            *
  108. .* Input:  &Opnd  = <id>[':' <size>] [ '[' <dim> ']']                         *
  109. .*         &Align = 1 ==> Align to word boundary and round size up to even    *
  110. .*                  0 ==> no alignment and no rounding                        *
  111. .*                                                                            *
  112. .* Output: None.                                                              *
  113. .*                                                                            *
  114. .* Code:   If <size> is a template name:      DS.W      <size>                *
  115. .*         If <size> is B, W, L, S, D, X, P:  DS.<size> <dim>         Note 1  *
  116. .*         If <size> anything else:           DS.B      <dim>*<size>  Note 2  *
  117. .*                                                                            *
  118. .*         Note 1: If <size>=B and &Align=1, then <size> forced to W          *
  119. .*         Note 2: If &Align=1, then <size> rounded to next word if odd       *
  120. .******************************************************************************
  121. .*
  122.         LCLC        &Var,&Size,&UCSize,&A[2]
  123.         LCLA        &VarLen,&i,&j,&Dim
  124. .*
  125.     &Var:    SETC &Trim(&Opnd)        ; Assume there is anly an <id> 
  126.     &VarLen: SETA &Len(&Opnd)        ; To be sure we look at last char
  127. .*
  128. .* Process '[' <dim> ']'
  129. .*
  130.     IF &Var[&VarLen] ≠ ']' THEN        ; Have "]" indicating we have <dim> ?
  131.       &Dim: SETA 1                    ; No, the <dim> defaults to 1
  132.     ELSE                            ; If we have a <dim>...
  133.       &i: SETA -&ScanEQ('[', &Var, -&VarLen) ; Find "[" preceding the <dim>
  134.       IF &i = &VarLen THEN            ; Did we find it ? (we better!)
  135.         AERROR '"[" missing.'        
  136.         &Dim: SETA 1                ; No, default to 1
  137.         &Var: SETA &Var[1:&VarLen-1]    ; Remove the invalid <dim> from the <id>
  138.       ELSE
  139.         &j:   SETA &VarLen-&i        ; If we have a valid <dim>
  140.         &Dim: SETA &Eval(&Var[&j+1:&i]); Extract it
  141.         &Var: SETC &Trim(&Var[1:&j-1]) ; Remove it from the <id>
  142.       ENDIF
  143.     ENDIF
  144. .*
  145. .* Process ':' <size>
  146. .*
  147.     &i:      SETA &List(&Var, '&A', ':')        ; Split <size> off the <id>
  148.     &Var:    SETC &Trim(&A[1])                ; Put <id> in &Var
  149.     &Size:   SETC &Default(&Trim(&A[2]), 'W')    ; Put <size> in &Size
  150.     &UCSize: SETC &UC(&Size)                    ; Need upper case copy to test
  151. .*
  152. .* Put it all together -- generate appropriate DC statement
  153. .*
  154.     IF &Type(&Size) = 'TEMPLATE' THEN
  155.       IF &Dim ≠ 1 THEN
  156.         AERROR 'Dimension must be 1 for template types'
  157.       ENDIF
  158. &Var      DS.W      &Size
  159.     ELSEIF (&UCSize = 'W') OR (&Align AND (&UCSize = 'B')) THEN
  160. &Var      DS.W      &Dim
  161.     ELSEIF (&Len(&UCSize) = 1) AND (&Pos(&UCSize, 'BLSDXP') > 0) THEN
  162. &Var      DS.&Size  &Dim
  163.     ELSE
  164.       &i: SETA &Ord(&Eval(&Size))
  165.       IF &Align THEN
  166. &Var      DS.B      &Dim*(&i+(&i**1))
  167.       ELSE
  168. &Var      DS.B      &Dim*&i
  169.       ENDIF
  170.     ENDIF
  171. .*
  172.         ENDM
  173.  
  174.  
  175.         TITLE    'Procedure - Parse a procedure declaration'
  176.         
  177.         MACRO
  178. &Scope    Procedure    &ArgList,&C,&Link==,&Main==N
  179. .*
  180. .******************************************************************************
  181. .* Procedure - Parse a procedure declaration                                  *
  182. .*                                                                            *
  183. .* Input:  &ArgList = <modname> ['('formal1,...formalN')'] [':'<result>]      *
  184. .*         <result> = B | W | L | S | D | X | P | <id>                        *
  185. .*         &Scope   = 'ENTRY'  ==> procedure local to file                    *
  186. .*                    'EXPORT' ==> procedure global to file                   *
  187. .*                    'LOCAL'  ==> procedure local to current procedure       *
  188. .*                    <null>   ==> same as ENTRY                              *
  189. .*         &C       = 'C' ==> a C routine, reverse args on the stack          *
  190. .*         &Link    = 'Y'     ==> generate LINK A6                            *
  191. .*                    'DEBUG' ==> generate LINK A6 and MacsBug symbol         *
  192. .*                    <null>  ==> generate LINK A6 if LinkAll or Debug is 1   *
  193. .*         &Main    = 'Y'     ==> main program                                *
  194. .*                    not 'Y' ==> not main program                            *
  195. .*                                                                            *
  196. .*         Globals: LinkAll ≠ 0 ==> always generate LINKs                     *
  197. .*                          = 0 ==> LINK's subject to &Link param             *
  198. .*                  Debug   ≠ 0 ==> always generate LINKs and MacsBug symbol  *
  199. .*                          = 0 ==> LINKs/MacsBug symbol subject to &Link     *
  200. .*                                                                            *
  201. .* Output: &StFrame#  = name of current stack frame (SF#xxxx)          (SETC) *
  202. .*         &DbgName#  = name to generate for MacsBug or <null>         (SETC) *
  203. .*         &FSz#      = function result size or <null>                 (SETC) *
  204. .*         &Link#     = 1 ==> generate LINK; 0 ==> no LINK             (SETA) *
  205. .*         &HaveDcls# = 1 ==> have local variables; 0 ==> no locals    (SETA) *
  206. .*         &C#        = 1 ==> C function; 0 ==> Pascal routine         (SETA) *
  207. .*                                                                            *
  208. .* Code: * The following is generated by Procedure (HERE IN THIS MACRO)       *
  209. .*       <modname> [PROC         &Scope]         ; PROC may be FUNC | MAIN    *
  210. .*       SF#xxxx    RECORD      {FramePtr},Decr  ; Local stack frame          *
  211. .*      [<modname>  DS.<result> 0]               ; Only if function           *
  212. .*       <formal1>  DS.<size>   <amount>         ; See Dcl1Var# for details   *
  213. .*                  - - -                                                     *
  214. .*       <formalN>  DS.<size>   <amount>         ; Reverse order if C funct   *
  215. .*       RetAddr    DS.L        1                ; Return address             *
  216. .*       -------------------------------------------------------------------- *
  217. .*       * The following is generated by Var                                  *
  218. .*       LinkA6     DS.L        1                ; LINK field before locals   *
  219. .*       FramePtr   EQU         *                ; A6 will point here         *
  220. .*       <Var1>     DS.<size>   <amount>         ; See Dcl1Var# for details   *
  221. .*                  - - -                                                     *
  222. .*       <VarN>     DS.<size>   <amount>         ; One DS for each Var arg    *
  223. .*       -------------------------------------------------------------------- *
  224. .*       * The following is generated by Begin                                *
  225. .*      [LinkA6     DS.L        1]               ; If required and no locals  *
  226. .*      [FramePtr   EQU         *]               ; A6 or A7 will point here   *
  227. .*       LocalSize  DS.W        0                ; Byte size of local vars    *
  228. .*                  ENDR                         ; End of local stack frame   *
  229. .*                  WITH       [<with>,]SF#xxxx  ; Cover templates, stk frame *
  230. .*                 [LINK        A6,#LocalSize]   ; If LINK is required        *
  231. .*       FP         SET         A6 or A7         ; A6 if LINK generated       *
  232. .*                 [MOVE[M].L   &Save,-(A7)]     ; If regs to save            *
  233. .*       -------------------------------------------------------------------- *
  234. .*       * The following is generated by Enter                                *
  235. .*                  BRA.S       %L%xxxx          ; Branch around Enter code   *
  236. .*       Lbl                                     ; 2ndary entry point label   *
  237. .*                 [WITH        <with>]          ; Cover additional templates *
  238. .*                 [LINK        A6,#LocalSize]   ; If LINK is required        *
  239. .*                 [MOVE[M].L   &Save,-(A7)]     ; If regs to save            *
  240. .*       %L%xxxx                                 ; The branch-around label    *
  241. .*       -------------------------------------------------------------------- *
  242. .*       * Body of procedure goes here                                        *
  243. .*       -------------------------------------------------------------------- *
  244. .*       * The following is generated by Return                               *
  245. .*                 [MOVE[M].L   (A7)+,<reg-list>]; Restore regs if any saved  *
  246. .*                 [UNLK        A6]              ; Only if LINK was done      *
  247. .*                 [MOVEA.L     (A7)+,A0     ]   ; If not C and have args...  *
  248. .*                 [ADD.W       #<ArgSize>,A7]   ; ...pop off arg list        *
  249. .*                 [MOVE.<size> <id>,(A7)]       ; If result for function     *
  250. .*                 [JMP         (A0)]            ; If not C and have args     *
  251. .*                 [RTS             ]            ; If C or no args            *
  252. .*                 [DC.B        '<modname>']     ; MacsBug symbol (asis str)  *
  253. .******************************************************************************
  254. .*
  255.         PRINT    Push,NoMDir,NoMCall
  256. .*
  257.         GBLC        &ModName#            ; <modname>
  258.         GBLC        &FInfo#            ; function <result>
  259.         GBLC        &Args#[50]        ; argument list
  260.         GBLA        &NbrOfArgs#        ; number of args in argument list
  261.         GBLC        &StFrame#            ; name of current stack frame
  262.         GBLC        &DbgName#            ; name to generate for MacsBug
  263.         GBLC        &FSz#            ; function result size
  264.         GBLA        &Link#            ; 1 ==> generate LINK
  265.         GBLA        &HaveDcls#        ; 1 ==> have local variables
  266.         GBLA        &C#                ; 1 ==> C function
  267.         GBLC        &Areg            ; "A" ==> call (An)[(arglist...)] case
  268. .*
  269.         LCLA        &Func,&Arg
  270.         LCLC        &LinkOpt
  271.         LCLC        &DbgTemp
  272. .*
  273. .* LinkAll is a user setable global controlling LINK generation
  274. .*
  275.     IF &Type('LinkAll') = 'UNDEFINED' THEN ; Initialize LinkAll if required
  276.       PRINT Push,Off
  277.       LinkAll: SET 0
  278.       PRINT Pop
  279.     ENDIF
  280. .*
  281. .* Debug is a user settable global controlling MacsBug symbol generation
  282. .*
  283.     IF &Type('Debug') = 'UNDEFINED' THEN ; Initialize Debug if required
  284.       PRINT Push,Off
  285.       Debug: SET 0
  286.       PRINT Pop
  287.     ENDIF
  288. .*
  289. .* Break up &ArgList into its components
  290. .*
  291.     &Areg: SETC ''                    ; Set switch for normal arglist
  292.     ScanArgs#    &ArgList                ; Set &ModName#, &Args#, &FInfo#
  293.     &Func: SETA &Len(&FInfo#)        ; &Func ≠ 0 if function
  294.     &C#:   SETA &UC(&C)='C'            ; Remember if we have a C function
  295. .*
  296.       IF &NbrOfArgs# = 1 THEN            ; Correct for the case F()
  297.           IF &Args#[1] = '' THEN            ; One arg but it's null...
  298.         &NbrOfArgs#: SETA 0            ; ...treat as if there are no arguments
  299.           ENDIF
  300.       ENDIF
  301. .*
  302. .* Generate module header and its corresponding scope
  303. .*
  304.     IF &UC(&Scope) = 'LOCAL' THEN
  305.           ALIGN
  306.       IF &ModName# ≠ '' THEN
  307. &ModName#:
  308.       ENDIF
  309.     ELSEIF &UC(&Main[1:1]) = 'Y' THEN
  310. &ModName# MAIN      &Scope
  311.     ELSEIF &Func THEN
  312. &ModName# FUNC      &Scope
  313.     ELSE
  314. &ModName# PROC      &Scope
  315.     ENDIF
  316. .*
  317. .* Start the proc's local stack frame
  318. .*
  319.     &StFrame#: SETC &Concat('SF#', &SysNdx)
  320. .*
  321. &StFrame# RECORD    {FramePtr},Decr
  322. .*
  323. .* If function, then generate stack fram label for function result. The label is
  324. .* the module name if function result is one of the standard sizes.  If it is not
  325. .* a standard size, it is assumed to be an <id> and that <id> is used as the
  326. .* function result label.
  327. .*
  328.     IF &Func THEN
  329.       IF (&Func = 1) AND (&Pos(&UC(&FInfo#), 'BWLSDXP') > 0) THEN
  330.         &FSz#: SETC &UC(&FInfo#)
  331. &ModName# DS.&FSz#  0
  332.       ELSE
  333.         &FSz#: SETC 'W'
  334. &FInfo#   DS.W        0
  335.       ENDIF
  336.     ELSE
  337.       &FSz#: SETC ''
  338.     ENDIF
  339. .*
  340. .* Declare all the formals in the local stack frame.  The formals are declared
  341. .* in the reverse order if we have a C function.
  342. .*
  343.     IF &C# THEN                    ; C ?
  344.       &Arg: SETA &NbrOfArgs#            ; Yes
  345.       WHILE &Arg > 0 DO                ; Declare formals in reverse order
  346.         Dcl1Var# &Args#[&Arg],1
  347.         &Arg: SETA &Arg-1
  348.       ENDW
  349.     ELSE                            ; Pascal
  350.       WHILE &Arg < &NbrOfArgs# DO        ; Declare formals in the "normal" way
  351.         &Arg: SETA &Arg+1
  352.         Dcl1Var# &Args#[&Arg],1      
  353.       ENDW
  354.     ENDIF
  355. .*
  356. .* The return address always follows the formal list
  357. .*
  358. RetAddr   DS.L      1
  359. .*
  360. .* Process the &Link parameter: indicates if LINK must be generated and whether
  361. .* MacsBug symbol will be generated.
  362. .*
  363.     &Link#:   SETA 0                ; Assume LINK will not be needed
  364.     &LinkOpt: SETC &UC(&Link)
  365.     IF Debug THEN                    ; If Debug ≠ 0 then...
  366.       &LinkOpt: SETC 'DEBUG'            ; ...we will gen LINK and MacsBug symbol
  367.     ELSEIF LinkAll THEN                ; If LinkAll ≠ 0 then...
  368.       IF &LinkOpt ≠ 'DEBUG' THEN        ; ...if user didn't specify DEBUG for &Link
  369.         &LinkOpt: SETC 'Y'            ; indicate we need the LINK
  370.       ENDIF
  371.     ENDIF
  372.     IF &LinkOpt ≠ '' THEN            ; Any &Link or global control setting ?
  373.       &Link#: SETA 1                ; Yes, set switch to gen LINK later
  374.       IF (&LinkOpt ≠ 'DEBUG') OR (&ModName# = '') THEN
  375.         &DbgName#: SETC ''            ; If no MacsBug symbol, set global <null>
  376.       ELSE                        ; If MacsBug symbol, set it to gen later
  377.         &DbgTemp: SETC    &ModName#        ; Generate new type symbols
  378.         IF &Len(&ModName#) < 32 THEN    ; If module name < 32 chars
  379.          IF &Len(&ModName#) // 2 = 0 THEN ; Add space if even so that...
  380.            &DbgTemp: SETC &Concat(&ModName#,' ') ; string length plus length byte...
  381.           ENDIF                    ; will align to word boundary
  382.           &DbgName#: SETC &Concat(&Chr($80 + &Len(&ModName#)), &DbgTemp)
  383.         ELSE                        ; Length is greater than 32 characters
  384.          IF &Len(&ModName#) // 2 = 1 THEN ; Add space if length is odd
  385.            &DbgTemp: SETC &Concat(&ModName#,' ')
  386.          ENDIF
  387.          &DbgName#: SETC &Concat(&Chr($80), &Chr(&Len(&ModName#)), &DbgTemp)
  388.         ENDIF
  389.       ENDIF
  390.     ENDIF
  391. .*
  392. .* That's all for now -- we have no local declarations at this point...yet!
  393. .*
  394.     &HaveDcls#: SETA 0
  395. .*
  396.         PRINT    Pop
  397.         ENDM
  398.  
  399.  
  400.         TITLE    'Function - Parse a function declaration'
  401.         
  402.         MACRO
  403. &Scope    Function    &ArgList,&C,&Link==,&Main==N
  404. .*
  405. .******************************************************************************
  406. .* Function - Parse a function declaration (see Procedure for details)        *
  407. .******************************************************************************
  408. .*                                                                            *
  409.         PRINT    Push,NoMDir,NoMCall
  410. .*
  411. &Scope    Procedure    &ArgList,&C,Link=&Link,Main=&Main
  412. .*
  413.         PRINT    Pop
  414.         ENDM
  415.  
  416.  
  417.         TITLE    'Var - Declare local variables on the stack'
  418.         
  419.         MACRO
  420.         Var
  421. .*
  422. .******************************************************************************
  423. .* Var - Declare local variables on the stack                                 *
  424. .*                                                                            *
  425. .* Call:   <var-id>  Var   <id>[':' <size>] [ '[' <dim> ']']   (See Dcl1Var#) *
  426. .*                                                                            *
  427. .* Input:  &HaveDcls# = 1 ==> have local variables; 0 ==> no locals    (SETA) *
  428. .*                                                                            *
  429. .* Output: &Link#     = 1 ==> generate LINK; 0 ==> no LINK             (SETA) *
  430. .*         &HaveDcls# = 1 ==> have local variables; 0 ==> no locals    (SETA) *
  431. .*                                                                            *
  432. .* Code: * The following is generated by Procedure                            *
  433. .*       <modname> [PROC         &Scope]         ; PROC may be FUNC | MAIN    *
  434. .*       SF#xxxx    RECORD      {FramePtr},Decr  ; Local stack frame          *
  435. .*      [<modname>  DS.<result> 0]               ; Only if function           *
  436. .*       <formal1>  DS.<size>   <amount>         ; See Dcl1Var# for details   *
  437. .*                  - - -                                                     *
  438. .*       <formalN>  DS.<size>   <amount>         ; Reverse order if C funct   *
  439. .*       RetAddr    DS.L        1                ; Return address             *
  440. .*       -------------------------------------------------------------------- *
  441. .*       * The following is generated by Var (HERE IN THIS MACRO)             *
  442. .*       LinkA6     DS.L        1                ; LINK field before locals   *
  443. .*       FramePtr   EQU         *                ; A6 will point here         *
  444. .*       <Var1>     DS.<size>   <amount>         ; See Dcl1Var# for details   *
  445. .*                  - - -                                                     *
  446. .*       <VarN>     DS.<size>   <amount>         ; One DS for each Var arg    *
  447. .*       -------------------------------------------------------------------- *
  448. .*       * The following is generated by Begin                                *
  449. .*      [LinkA6     DS.L        1]               ; If required and no locals  *
  450. .*      [FramePtr   EQU         *]               ; A6 or A7 will point here   *
  451. .*       LocalSize  DS.W        0                ; Byte size of local vars    *
  452. .*                  ENDR                         ; End of local stack frame   *
  453. .*                  WITH       [<with>,]SF#xxxx  ; Cover templates, stk frame *
  454. .*                 [LINK        A6,#LocalSize]   ; If LINK is required        *
  455. .*       FP         SET         A6 or A7         ; A6 if LINK generated       *
  456. .*                 [MOVE[M].L   &Save,-(A7)]     ; If regs to save            *
  457. .*       -------------------------------------------------------------------- *
  458. .*       * The following is generated by Enter                                *
  459. .*                  BRA.S       %L%xxxx          ; Branch around Enter code   *
  460. .*       Lbl                                     ; 2ndary entry point label   *
  461. .*                 [WITH        <with>]          ; Cover additional templates *
  462. .*                 [LINK        A6,#LocalSize]   ; If LINK is required        *
  463. .*                 [MOVE[M].L   &Save,-(A7)]     ; If regs to save            *
  464. .*       %L%xxxx                                 ; The branch-around label    *
  465. .*       -------------------------------------------------------------------- *
  466. .*       * Body of procedure goes here                                        *
  467. .*       -------------------------------------------------------------------- *
  468. .*       * The following is generated by Return                               *
  469. .*                 [MOVE[M].L   (A7)+,<reg-list>]; Restore regs if any saved  *
  470. .*                 [UNLK        A6]              ; Only if LINK was done      *
  471. .*                 [MOVEA.L     (A7)+,A0     ]   ; If not C and have args...  *
  472. .*                 [ADD.W       #<ArgSize>,A7]   ; ...pop off arg list        *
  473. .*                 [MOVE.<size> <id>,(A7)]       ; If result for function     *
  474. .*                 [JMP         (A0)]            ; If not C and have args     *
  475. .*                 [RTS             ]            ; If C or no args            *
  476. .*                 [DC.B        '<modname>']     ; MacsBug symbol (asis str)  *
  477. .******************************************************************************
  478. .*
  479.         PRINT    Push,NoMDir,NoMCall
  480. .*
  481.         GBLA        &Link#            ; 1 ==> generate LINK
  482.         GBLA        &HaveDcls#        ; 1 ==> have local variables
  483. .*
  484.         LCLA        &i,&N
  485. .*
  486.     IF NOT &HaveDcls# THEN            ; Is this the first local declaration ?
  487.       &HaveDcls#: SETA 1            ; Yes, indicate we have locals
  488. LinkA6    DS.L      1
  489. FramePtr  EQU       *
  490.     ENDIF
  491. .*
  492. .* Declare each variable on the &SysLst argument list using Dcl1Var#.  Thus the
  493. .* syntax for local variables is identical to proc formals except that here the
  494. .* word alignment is not required.
  495. .*
  496.     &N: SETA &Nbr(&SysLst)
  497.     WHILE &i < &N DO                ; Around and around we go...
  498.       &i: SETA &i+1
  499.       Dcl1Var# &SysLst[&i],0
  500.     ENDW
  501. .*
  502.     &Link#: SETA 1                    ; Now we will require a LINK
  503. .*
  504.         PRINT    Pop
  505.         ENDM
  506.  
  507.         
  508.         TITLE    'Begin - Procedure primary entry point'
  509.         
  510.         MACRO
  511.         Begin    &Prelude,&Save==,&With==
  512. .*
  513. .******************************************************************************
  514. .* Begin - Procedure primary entry point                                      *
  515. .*                                                                            *
  516. .* Input:  &Prelude   = not <null> ==> override generation of LINK            *
  517. .*         &Save      = a register list of regs to save across this procedure *
  518. .*         &With      = a sublist of additional templates to cover with WITH  *
  519. .*                                                                            *
  520. .*         &StFrame#  = name of current stack frame (SF#xxxx)          (SETC) *
  521. .*         &Link#     = 1 ==> generate LINK; 0 ==> no LINK             (SETA) *
  522. .*         &HaveDcls# = 1 ==> have local variables; 0 ==> no locals    (SETA) *
  523. .*                                                                            *
  524. .* Output: &Link#     = 1 ==> generate LINK; 0 ==> no LINK             (SETA) *
  525. .*         &SaveRegs# = Regs saved and to be restored                  (SETC) *
  526. .*         &ArgSize#  = nbr of bytes of stack space for formals        (SETA) *
  527. .*                                                                            *
  528. .* Code: * The following is generated by Procedure                            *
  529. .*       <modname> [PROC         &Scope]         ; PROC may be FUNC | MAIN    *
  530. .*       SF#xxxx    RECORD      {FramePtr},Decr  ; Local stack frame          *
  531. .*      [<modname>  DS.<result> 0]               ; Only if function           *
  532. .*       <formal1>  DS.<size>   <amount>         ; See Dcl1Var# for details   *
  533. .*                  - - -                                                     *
  534. .*       <formalN>  DS.<size>   <amount>         ; Reverse order if C funct   *
  535. .*       RetAddr    DS.L        1                ; Return address             *
  536. .*       -------------------------------------------------------------------- *
  537. .*       * The following is generated by Var                                  *
  538. .*       LinkA6     DS.L        1                ; LINK field before locals   *
  539. .*       FramePtr   EQU         *                ; A6 will point here         *
  540. .*       <Var1>     DS.<size>   <amount>         ; See Dcl1Var# for details   *
  541. .*                  - - -                                                     *
  542. .*       <VarN>     DS.<size>   <amount>         ; One DS for each Var arg    *
  543. .*       -------------------------------------------------------------------- *
  544. .*       * The following is generated by Begin (HERE IN THIS MACRO)           *
  545. .*      [LinkA6     DS.L        1]               ; If required and no locals  *
  546. .*      [FramePtr   EQU         *]               ; A6 or A7 will point here   *
  547. .*       LocalSize  DS.W        0                ; Byte size of local vars    *
  548. .*                  ENDR                         ; End of local stack frame   *
  549. .*                  WITH       [<with>,]SF#xxxx  ; Cover templates, stk frame *
  550. .*                 [LINK        A6,#LocalSize]   ; If LINK is required        *
  551. .*       FP         SET         A6 or A7         ; A6 if LINK generated       *
  552. .*                 [MOVE[M].L   &Save,-(A7)]     ; If regs to save            *
  553. .*       -------------------------------------------------------------------- *
  554. .*       * The following is generated by Enter                                *
  555. .*                  BRA.S       %L%xxxx          ; Branch around Enter code   *
  556. .*       Lbl                                     ; 2ndary entry point label   *
  557. .*                 [WITH        <with>]          ; Cover additional templates *
  558. .*                 [LINK        A6,#LocalSize]   ; If LINK is required        *
  559. .*                 [MOVE[M].L   &Save,-(A7)]     ; If regs to save            *
  560. .*       %L%xxxx                                 ; The branch-around label    *
  561. .*       -------------------------------------------------------------------- *
  562. .*       * Body of procedure goes here                                        *
  563. .*       -------------------------------------------------------------------- *
  564. .*       * The following is generated by Return                               *
  565. .*                 [MOVE[M].L   (A7)+,<reg-list>]; Restore regs if any saved  *
  566. .*                 [UNLK        A6]              ; Only if LINK was done      *
  567. .*                 [MOVEA.L     (A7)+,A0     ]   ; If not C and have args...  *
  568. .*                 [ADD.W       #<ArgSize>,A7]   ; ...pop off arg list        *
  569. .*                 [MOVE.<size> <id>,(A7)]       ; If result for function     *
  570. .*                 [JMP         (A0)]            ; If not C and have args     *
  571. .*                 [RTS             ]            ; If C or no args            *
  572. .*                 [DC.B        '<modname>']     ; MacsBug symbol (asis str)  *
  573. .******************************************************************************
  574. .*
  575.         PRINT    Push,NoMDir,NoMCall
  576. .*
  577.         GBLC        &FInfo#            ; function <result>
  578.         GBLC        &StFrame#            ; name of current stack frame
  579.         GBLC        &SaveRegs#        ; Regs saved and to be restored
  580.         GBLA        &NbrOfArgs#        ; number of args in argument list
  581.         GBLA        &Link#            ; 1 ==> generate LINK
  582.         GBLA        &HaveDcls#        ; 1 ==> have local variables
  583.         GBLA        &ArgSize#            ; nbr of bytes of stack space for formals
  584. .*
  585. .* If we don't already think we need a LINK, we still may need it if, at this
  586. .* point, we have to save registers and we are in a function or there are formal
  587. .* parameters.
  588. .*
  589.     IF &Link# OR (((&FInfo#≠'') OR (&NbrOfArgs# ≠ 0)) AND (&Save≠'')) THEN
  590.       &Link#: SETA 1                ; Link is required
  591.       IF NOT &HaveDcls# THEN            ; Gen field for LINK address if no locals
  592. LinkA6    DS.L      1
  593.       ENDIF
  594.     ENDIF
  595. .*
  596. .* If there we no locals, we haven't generated the FramePtr yet.  So we do it now.
  597. .*
  598.     IF NOT &HaveDcls# THEN
  599. FramePtr  EQU       *
  600.     ENDIF
  601. .*
  602. .* That's all for the stack frame. We generate LocalSize to be used in potential
  603. .* LINK instruction.
  604. .*
  605. LocalSize DS.W      0
  606.           ENDR
  607. .*
  608. .* Generate a WITH to cover the local stack frame and any additional templates
  609. .* the user specified in the &With parameter.  This may be a sublist or a single
  610. .* name.
  611. .*
  612.     IF &With ≠ '' THEN
  613.       IF &With[1:1] = '(' THEN
  614.           WITH      &With[2:&Len(&With)-2],&StFrame#
  615.       ELSE
  616.           WITH      &With,&StFrame#
  617.       ENDIF
  618.     ELSE
  619.           WITH      &StFrame#
  620.     ENDIF
  621. .*
  622. .* It's time for the LINK.  It is generated if &Link is 1.  &Link became 1 under
  623. .* the following conditions:
  624. .*   1. Either the globals LinkAll or Debug are set non-zero.
  625. .*   2. The &Link Procedure parameter is set to DEBUG or non-null
  626. .*   3. There are local variables (Var's)
  627. .*   4. There are registers to save (&Save), and
  628. .*      • we are processing a function, or
  629. .*      • there are formal (and, of course, actual) parameters
  630. .* Given all this, the user can still suppress the LINK by setting &Prelude to
  631. .* non-null.
  632. .*
  633.     IF &Link# THEN
  634.       IF &Prelude = '' THEN
  635.           LINK      A6,#LocalSize
  636.       ENDIF
  637. FP        SET       A6
  638.     ELSE
  639. FP        SET       A7
  640.     ENDIF
  641. .*
  642. .* Compute the size of the argument list to be able to pop the stack with Return.
  643. .* Also, save registers if required.
  644. .*
  645.     &ArgSize#:  SETA &Eval(&StFrame#)-RetAddr-4
  646.     &SaveRegs#: SETC &Save
  647.     IF &Save ≠ '' THEN
  648.       IF &Substr(&Type(&Save), 1, 3) = 'REG' THEN
  649.           MOVE.L    &Save,-(A7)
  650.       ELSE
  651.           MOVEM.L   &Save,-(A7)
  652.       ENDIF
  653.     ENDIF
  654. .*
  655.         PRINT    Pop
  656.         ENDM
  657.  
  658.         
  659.         TITLE    'Enter - Procedure secondary entry point'
  660.         
  661.         MACRO
  662. &Lbl        Enter    &Prelude,&With==
  663. .*
  664. .******************************************************************************
  665. .* Enter - Procedure secondary entry point                                    *
  666. .*                                                                            *
  667. .* Input:  &Prelude   = not <null> ==> override generation of LINK            *
  668. .*         &With      = a sublist of additional templates to cover with WITH  *
  669. .*                                                                            *
  670. .*         &Link#     = 1 ==> generate LINK; 0 ==> no LINK             (SETA) *
  671. .*         &SaveRegs# = Regs saved and to be restored                  (SETC) *
  672. .*                                                                            *
  673. .* Output: None.                                                              *
  674. .*                                                                            *
  675. .* Code: * The following is generated by Procedure                            *
  676. .*       <modname> [PROC         &Scope]         ; PROC may be FUNC | MAIN    *
  677. .*       SF#xxxx    RECORD      {FramePtr},Decr  ; Local stack frame          *
  678. .*      [<modname>  DS.<result> 0]               ; Only if function           *
  679. .*       <formal1>  DS.<size>   <amount>         ; See Dcl1Var# for details   *
  680. .*                  - - -                                                     *
  681. .*       <formalN>  DS.<size>   <amount>         ; Reverse order if C funct   *
  682. .*       RetAddr    DS.L        1                ; Return address             *
  683. .*       -------------------------------------------------------------------- *
  684. .*       * The following is generated by Var                                  *
  685. .*       LinkA6     DS.L        1                ; LINK field before locals   *
  686. .*       FramePtr   EQU         *                ; A6 will point here         *
  687. .*       <Var1>     DS.<size>   <amount>         ; See Dcl1Var# for details   *
  688. .*                  - - -                                                     *
  689. .*       <VarN>     DS.<size>   <amount>         ; One DS for each Var arg    *
  690. .*       -------------------------------------------------------------------- *
  691. .*       * The following is generated by Begin                                *
  692. .*      [LinkA6     DS.L        1]               ; If required and no locals  *
  693. .*      [FramePtr   EQU         *]               ; A6 or A7 will point here   *
  694. .*       LocalSize  DS.W        0                ; Byte size of local vars    *
  695. .*                  ENDR                         ; End of local stack frame   *
  696. .*                  WITH       [<with>,]SF#xxxx  ; Cover templates, stk frame *
  697. .*                 [LINK        A6,#LocalSize]   ; If LINK is required        *
  698. .*       FP         SET         A6 or A7         ; A6 if LINK generated       *
  699. .*                 [MOVE[M].L   &Save,-(A7)]     ; If regs to save            *
  700. .*       -------------------------------------------------------------------- *
  701. .*       * The following is generated by Enter (HERE IN THIS MACRO)           *
  702. .*                  BRA.S       %L%xxxx          ; Branch around Enter code   *
  703. .*       Lbl                                     ; 2ndary entry point label   *
  704. .*                 [WITH        <with>]          ; Cover additional templates *
  705. .*                 [LINK        A6,#LocalSize]   ; If LINK is required        *
  706. .*                 [MOVE[M].L   &Save,-(A7)]     ; If regs to save            *
  707. .*       %L%xxxx                                 ; The branch-around label    *
  708. .*       -------------------------------------------------------------------- *
  709. .*       * Body of procedure goes here                                        *
  710. .*       -------------------------------------------------------------------- *
  711. .*       * The following is generated by Return                               *
  712. .*                 [MOVE[M].L   (A7)+,<reg-list>]; Restore regs if any saved  *
  713. .*                 [UNLK        A6]              ; Only if LINK was done      *
  714. .*                 [MOVEA.L     (A7)+,A0     ]   ; If not C and have args...  *
  715. .*                 [ADD.W       #<ArgSize>,A7]   ; ...pop off arg list        *
  716. .*                 [MOVE.<size> <id>,(A7)]       ; If result for function     *
  717. .*                 [JMP         (A0)]            ; If not C and have args     *
  718. .*                 [RTS             ]            ; If C or no args            *
  719. .*                 [DC.B        '<modname>']     ; MacsBug symbol (asis str)  *
  720. .******************************************************************************
  721. .*
  722.         PRINT    Push,NoMDir,NoMCall
  723. .*
  724.         GBLC        &SaveRegs#        ; Regs saved and to be restored
  725.         GBLA        &Link#            ; 1 ==> generate LINK
  726. .*
  727. .* Generate a branch around the Enter code
  728. .*
  729.           BRA.S     %L%&SysNdx
  730. &Lbl ;
  731. .*
  732. .* Generate a WITH to cover any additional templates  the user specified in the
  733. .* &With parameter.  This may be a sublist or a single name.
  734. .*
  735.     IF &With ≠ '' THEN
  736.       IF &With[1:1] = '(' THEN
  737.           WITH      &With[2:&Len(&With)-2]
  738.       ELSE
  739.           WITH      &With
  740.       ENDIF
  741.     ENDIF
  742. .*
  743. .* It's time for another LINK.  It is generated if &Link is 1.  &Link became 1
  744. .* under the following conditions:
  745. .*   1. Either the globals LinkAll or Debug are set non-zero.
  746. .*   2. The &Link Procedure parameter is set to DEBUG or non-null
  747. .*   3. There are local variables (Var's)
  748. .*   4. There are registers to save (&Save), and
  749. .*      • we are processing a function, or
  750. .*      • there are formal (and, of course, actual) parameters
  751. .* Given all this, the user can still suppress the LINK by setting &Prelude to
  752. .* non-null.
  753. .*
  754.     IF &Link# THEN
  755.       IF &Prelude = '' THEN
  756.           LINK      A6,#LocalSize
  757.       ENDIF
  758.     ENDIF
  759. .*
  760. .* Save registers if required.
  761. .*
  762.     IF &SaveRegs# ≠ '' THEN
  763.       IF &Substr(&Type(&SaveRegs#), 1, 3) = 'REG' THEN
  764.           MOVE.L    &SaveRegs#,-(A7)
  765.       ELSE
  766.           MOVEM.L   &SaveRegs#,-(A7)
  767.       ENDIF
  768.     ENDIF
  769. .*
  770. .*
  771. .* The Enter branch-around label follows all the Enter code to allow code before
  772. .* the Enter to jump over the Enter.
  773. .*
  774. %L%&SysNdx
  775. .*
  776.         PRINT    Pop
  777.         ENDM
  778.  
  779.  
  780.         TITLE    'Return - Procedure and function exit'
  781.         
  782.         MACRO
  783.         Return    &Result
  784. .*
  785. .******************************************************************************
  786. .* Return - Procedure and function exit                                       *
  787. .*                                                                            *
  788. .* Input:  &Result    = [ <ea> [':' <size> ]                                  *
  789. .*         <size>     = B | W | L | S | D | X | P                             *
  790. .*                                                                            *
  791. .*         &SaveRegs# = Regs saved and to be restored                  (SETC) *
  792. .*         &DbgName#  = name to generate for MacsBug or <null>         (SETC) *
  793. .*         &FSz#      = function result size or <null>                 (SETC) *
  794. .*         &Link#     = 1 ==> generate LINK; 0 ==> no LINK             (SETA) *
  795. .*         &ArgSize#  = nbr of bytes of stack space for formals        (SETA) *
  796. .*         &C#        = 1 ==> C function; 0 ==> Pascal routine         (SETA) *
  797. .*                                                                            *
  798. .* Code: * The following is generated by Procedure                            *
  799. .*       <modname> [PROC         &Scope]         ; PROC may be FUNC | MAIN    *
  800. .*       SF#xxxx    RECORD      {FramePtr},Decr  ; Local stack frame          *
  801. .*      [<modname>  DS.<result> 0]               ; Only if function           *
  802. .*       <formal1>  DS.<size>   <amount>         ; See Dcl1Var# for details   *
  803. .*                  - - -                                                     *
  804. .*       <formalN>  DS.<size>   <amount>         ; Reverse order if C funct   *
  805. .*       RetAddr    DS.L        1                ; Return address             *
  806. .*       -------------------------------------------------------------------- *
  807. .*       * The following is generated by Var                                  *
  808. .*       LinkA6     DS.L        1                ; LINK field before locals   *
  809. .*       FramePtr   EQU         *                ; A6 will point here         *
  810. .*       <Var1>     DS.<size>   <amount>         ; See Dcl1Var# for details   *
  811. .*                  - - -                                                     *
  812. .*       <VarN>     DS.<size>   <amount>         ; One DS for each Var arg    *
  813. .*       -------------------------------------------------------------------- *
  814. .*       * The following is generated by Begin                                *
  815. .*      [LinkA6     DS.L        1]               ; If required and no locals  *
  816. .*      [FramePtr   EQU         *]               ; A6 or A7 will point here   *
  817. .*       LocalSize  DS.W        0                ; Byte size of local vars    *
  818. .*                  ENDR                         ; End of local stack frame   *
  819. .*                  WITH       [<with>,]SF#xxxx  ; Cover templates, stk frame *
  820. .*                 [LINK        A6,#LocalSize]   ; If LINK is required        *
  821. .*       FP         SET         A6 or A7         ; A6 if LINK generated       *
  822. .*                 [MOVE[M].L   <reg-list>,-(A7)]; If regs to save            *
  823. .*       -------------------------------------------------------------------- *
  824. .*       * The following is generated by Enter                                *
  825. .*                  BRA.S       %L%xxxx          ; Branch around Enter code   *
  826. .*       Lbl                                     ; 2ndary entry point label   *
  827. .*                 [WITH        <with>]          ; Cover additional templates *
  828. .*                 [LINK        A6,#LocalSize]   ; If LINK is required        *
  829. .*                 [MOVE[M].L   &Save,-(A7)]     ; If regs to save            *
  830. .*       %L%xxxx                                 ; The branch-around label    *
  831. .*       -------------------------------------------------------------------- *
  832. .*       * Body of procedure goes here                                        *
  833. .*       -------------------------------------------------------------------- *
  834. .*       * The following is generated by Return (HERE IN THIS MACRO)          *
  835. .*                 [MOVE[M].L   (A7)+,<reg-list>]; Restore regs if any saved  *
  836. .*                 [UNLK        A6]              ; Only if LINK was done      *
  837. .*                 [MOVEA.L     (A7)+,A0     ]   ; If not C and have args...  *
  838. .*                 [ADD.W       #<ArgSize>,A7]   ; ...pop off arg list        *
  839. .*                 [MOVE.<size> <ea>,(A7)]       ; If result for function     *
  840. .*                 [JMP         (A0)]            ; If not C and have args     *
  841. .*                 [RTS             ]            ; If C or no args            *
  842. .*                 [DC.B        '<modname>']     ; MacsBug symbol (asis str)  *
  843. .******************************************************************************
  844. .*
  845.         PRINT    Push,NoMDir,NoMCall
  846. .*
  847.         GBLC        &SaveRegs#        ; Regs saved and to be restored
  848.         GBLC        &DbgName#            ; name to generate for MacsBug
  849.         GBLC        &FSz#            ; function result size
  850.         GBLA        &Link#            ; 1 ==> generate LINK
  851.         GBLA        &ArgSize#            ; nbr of bytes of stack space for formals
  852.         GBLA        &C#                ; 1 ==> C function
  853. .*
  854.         LCLC        &S,&Rslt[2]
  855.         LCLA        &i
  856. .*
  857. .* Gen code to restore any save registers
  858. .*
  859.     IF &SaveRegs# ≠ '' THEN
  860.       IF &Substr(&Type(&SaveRegs#), 1, 3) = 'REG' THEN
  861.           MOVE.L    (A7)+,&SaveRegs#
  862.       ELSE
  863.           MOVEM.L   (A7)+,&SaveRegs#
  864.       ENDIF
  865.     ENDIF
  866. .*
  867. .* If we generated the LINK, it's time for the UNLK
  868. .*
  869.     IF &Link# THEN
  870.           UNLK      A6
  871.     ENDIF
  872. .*
  873. .* Generate procedure return to caller: if we are doing a C function, just do an
  874. .* RTS, since it's the caller's responsibility to pop the args off the stack.  If
  875. .* we are generating a Pascal routine, then again we only need an RTS if there
  876. .* were no arguments.  If there were, we pop the arguments off the stack by
  877. .* adding the arg size to A7.  The assembler will optimize the ADD appropriately.
  878. .* Once the arguments are popped we can set the function result using &Result.
  879. .* If no result and one long arg, use MOVE.L (A7)+,(A7) followed by an RTS.
  880. .*
  881.     IF &C# THEN                    ; Just RTS if C function
  882.              RTS
  883.     ELSEIF (&Result = '') AND (&ArgSize# = 4) THEN ;special Pascal case...
  884.         MOVE.L    (A7)+,(A7)
  885.         RTS
  886.     ELSE                            ; If Pascal...
  887.       IF &ArgSize# > 8 THEN            ; Pop stack if there are args
  888.           MOVEA.L   (A7)+,A0
  889.           LEA       &ArgSize#(A7),A7
  890.       ELSEIF &ArgSize# THEN
  891.           MOVEA.L   (A7)+,A0
  892.           ADD.W     #&ArgSize#,A7
  893.       ELSEIF &Result ≠ '' THEN
  894.           MOVEA.L   (A7)+,A0
  895.       ENDIF
  896.       IF &Result ≠ '' THEN            ; Returning a result to a function ?
  897.         IF &FSz# = '' THEN            ; Yes, we better be in a function!
  898.           AERROR 'Attempt to return a function result in a procedure'
  899.         ELSE                        ; So far, so good
  900.          &i: SETA &List(&Result, '&Rslt', ':')        ; Split &Result
  901.          &S: SETC &Default(&UC(&Trim(&Rslt[2])), &FSz#)    ; Use size override if any
  902.          IF &Pos(&S, 'BWL') THEN        ; B | W | L ==> assume normal MOVE
  903.           MOVE.&S   &Trim(&Rslt[1]),(A7)
  904.          ELSE                    ; S | D | X | P ==> floating point
  905.           FMOVE.&S   &Trim(&Rslt[1]),(A7)
  906.          ENDIF
  907.         ENDIF
  908.       ENDIF
  909.       IF &ArgSize# OR (&Result ≠ '') THEN
  910.           JMP       (A0)
  911.       ELSE
  912.           RTS
  913.       ENDIF
  914.     ENDIF
  915. .*
  916. .* If we need to generate the MacsBug symbol, now is the time!  Be careful to
  917. .* make sure of the Assembler's STRING setting, since the MacsBug symbol must
  918. .* be an ASIS string.
  919. .*
  920.     IF &DbgName# ≠ '' THEN            ; &DbgName# indicates we have a symbol
  921.       &S: SETC &Setting('STRING')        ; Preserve STRING status
  922.       IF &S ≠ 'ASIS' THEN            ; Only change it if not already ASIS
  923.           STRING    ASIS
  924.           DC.B      '&DbgName#'
  925.           STRING    &S
  926.       ELSE
  927.           DC.B      '&DbgName#'
  928.       ENDIF
  929.       DC.W        0                ; Fake literal size
  930.     ENDIF
  931. .*
  932.         PRINT    Pop
  933.         ENDM
  934.  
  935.  
  936.         TITLE    'Call - procedure, function, or trap call'
  937.         
  938.         MACRO
  939.         Call.&Ext    &CallSpec,&Result
  940. .*
  941. .******************************************************************************
  942. .* Call - procedure, function, or trap call                                   *
  943. .*                                                                            *
  944. .* Input:  &Ext      = S | B | W | L | * | A| <null>                          *
  945. .*         &CallSpec = <modname>[':'<size>] ['('arg1,...argN')'] |            *
  946. .*                   (An)['('arg1,...argN')'] if "A" Ext                   *
  947. .*         &Result   = PASS | {<id> | CC | POP} [':' <size>] |                *
  948. .*                     (PASS,{<id> | CC} [':' <size>])                        *
  949. .*                                                                            *
  950. .*         <size>    = B | W | L                                              *
  951. .*         <arg-i>   = <null> | NIL | TRUE | FALSE |                          *
  952. .*                     <ea> [':' {<size> | <reg> | A } ]                      *
  953. .*                                                                            *
  954. .*         Global:  AutoImport ≠ 0 ==> Gen IMPORT for undefined modname       *
  955. .*                             = 0 ==> Do not gen IMPORT                      *
  956. .*                                                                            *
  957. .* Code: [SUBQ.W    #2|4,A7    ]       ; If function call                     *
  958. .*                                                                            *
  959. .*       [PEA       <arg>      ]       ; If arg:A                             *
  960. .*       [MOVEQ     <arg>,<reg>]       ; If <arg>:<reg>                       *
  961. .*       [MOVE.L    <reg>,-(A7)]       ;  "   "     "                         *
  962. .*       [MOVE.<sz> <arg>,-(A7)]       ; If <arg>:<sz>                        *
  963. .*                                                                            *
  964. .*       [JSR       <modname>  ]       ; If calling code module or import     *
  965. .*       [BSR.<sz>  <modname>  ]       ; If explicit size and not <sz>='*'    *
  966. .*       [<modname>            ]       ; If OPWORD, macro, or "_undefined"    *
  967. .*                                                                            *
  968. .*       [TST.<sz>  (A7)+      ]       ; If result = CC:<sz>                  *
  969. .*       [ADDQ.W    #2|4,A7    ]       ; If result = POP:<sz>                 *
  970. .*       [MOVE.<sz> (A7)+,Rslt ]       ; If result = <rslt>:<sz>              *
  971. .******************************************************************************
  972. .*
  973.         PRINT    Push,NoMDir,NoMCall
  974. .*
  975.         GBLC        &ModName#            ; <modname>
  976.         GBLC        &Args#[50]        ; argument list
  977.         GBLA        &NbrOfArgs#        ; number of args in argument list
  978.         GBLC        &FInfo#            ; Function type if parameterless funct
  979.         GBLC        &Areg            ; "A" ==> call (An)[(arglist...)] case
  980. .*
  981.         LCLA        &i,&Arg
  982.         LCLC        &A[2],&Sz,&Param,&T,&Rslt,&RsltSz
  983. .*
  984. .* AutoImport is a user settable global controlling automatic IMPORT generation
  985. .*
  986.     IF &Type('AutoImport') = 'UNDEFINED' THEN ; Initialize AutoImport if required
  987.       PRINT Push,Off
  988.       AutoImport: SET 0
  989.       PRINT Pop
  990.     ENDIF
  991. .*
  992. .* Split up the call statement into the globals
  993. .*
  994.     &Areg: SETC &UC(&Ext)            ; Set sw to "A" for (An)[(arglist...)] case
  995.     ScanArgs# &CallSpec                ; Set &ModName#, &Args#, &NbrOfArgs#
  996. .*
  997. .* See if we are calling function as indicated by a size on the <modname>. If
  998. .* we are, split off the size from the <modname>, and set &RsltSz with the size
  999. .* to pop off the stack after the call (unless overridden by the &Result param).
  1000. .* Reserve space now for the function result.
  1001. .*
  1002.     IF &NbrOfArgs# = 0 THEN
  1003.       &RsltSz: SETC &Default(&UC(&FInfo#), 'W')
  1004.       IF &FInfo# ≠ '' THEN
  1005.         IF &RsltSz = 'L' THEN
  1006.           SUBQ.W    #4,A7
  1007.         ELSE
  1008.           SUBQ.W    #2,A7
  1009.         ENDIF
  1010.       ENDIF
  1011.     ELSE
  1012.       &i:       SETA &List(&ModName#, '&A', ':')
  1013.       &ModName#: SETC &Trim(&A[1])
  1014.       &RsltSz:   SETC &Default(&UC(&Trim(&A[2])), 'W')
  1015.       IF &i = 2 THEN
  1016.         IF &RsltSz = 'L' THEN
  1017.           SUBQ.W    #4,A7
  1018.         ELSE
  1019.           SUBQ.W    #2,A7
  1020.         ENDIF
  1021.       ENDIF
  1022.     ENDIF
  1023. .*
  1024. .* Push each argument on the stack.
  1025. .*
  1026.     WHILE &Arg < &NbrOfArgs# DO            ; Loop through all of 'em
  1027.       &Arg:   SETA &Arg+1
  1028.       &A[2]:  SETC ''
  1029.       &i:     SETA &List(&Args#[&Arg], '&A', ':'); Split arg to get its size
  1030.       &Param: SETC &Trim(&A[1])            ; Here's the arg
  1031.       IF &Param ≠ '' THEN                ; I hope, it could be null
  1032.         &Sz: SETC &Default(&UC(&Trim(&A[2])), 'W'); Get arg size
  1033.         IF &Sz = 'A' THEN                ; Should we push address ?
  1034.           PEA       &Param
  1035.         ELSEIF &SubStr(&Type(&Sz), 1, 3) = 'REG' THEN ; Pushing a reg value ?
  1036.           MOVEQ     &Param,&Sz
  1037.           MOVE.L    &Sz,-(A7)
  1038.         ELSE
  1039.              IF &A[2] = '' THEN
  1040.            &T: SETC &UC(&Param)
  1041.             IF &T = 'NIL' THEN            ; Pushing NIL ?
  1042.           CLR.L     -(A7)
  1043.             ELSEIF &T = 'TRUE' THEN        ; Pushing TRUE ?
  1044.           ST        -(A7)
  1045.            ELSEIF &T = 'FALSE' THEN        ; Pushing FALSE ?
  1046.           CLR.B     -(A7)
  1047.             ELSE                        ; Pushing a simple <ea>
  1048.           MOVE.&Sz  &Param,-(A7)
  1049.            ENDIF
  1050.          ELSE                        ; Pushing a simple <ea>
  1051.           MOVE.&Sz  &Param,-(A7)
  1052.          ENDIF
  1053.         ENDIF
  1054.       ENDIF
  1055.     ENDW
  1056. .*
  1057. .* Call the procedure or trap. If the size is "*" or we are calling a import, or
  1058. .* we are calling another module, do a JSR.  If we are calling an OPWORD, macro,
  1059. .* or some undefined name that begins with an underscore, use the name as the
  1060. .* call.  In all other cases we BSR to the called routine.
  1061. .*
  1062.     &Sz: SETC &UC(&Ext)
  1063.     IF &Sz = 'A' THEN
  1064.         JSR        &ModName#
  1065.     ELSEIF (&Sz ≠ '*') AND (&Sz ≠ '') THEN
  1066.           BSR.&Sz   &ModName#
  1067.     ELSE
  1068.       &T: SETC &SubStr(&Type(&ModName#), 1, 11)
  1069.       IF &Sz = '*' THEN
  1070.           JSR       &ModName#
  1071.       ELSEIF (&T = 'OPWORD') OR (&T = 'MACRO') OR ((&T='UNDEFINED') AND (&ModName#[1] = '_')) THEN
  1072.           &ModName#
  1073.       ELSEIF (&T='CODE MODULE') OR (&T='CODE IMPORT') OR (&T='UNDEFINED') THEN
  1074.         IF AutoImport AND (&T = 'UNDEFINED') THEN
  1075.          Import    &ModName#
  1076.         ENDIF
  1077.           JSR       &ModName#
  1078.       ELSE
  1079.           BSR       &ModName#
  1080.       ENDIF
  1081.     ENDIF
  1082. .*
  1083. .* If there is an explicit &Result override, we use it to determine what to do
  1084. .* with function's returned value.  Above, the function invocation possibly
  1085. .* was specified as part of a size attribute on the modname.  That size could
  1086. .* be overridden here with a size attribute on the result.  Whichever way we get
  1087. .* it it is used to pop the function result off the stack (if PASS isn't used).
  1088. .*
  1089.     &Rslt: SETC &Default(&Result, 'PASS'); Default result to PASS
  1090.     IF &UC(&Rslt) ≠ 'PASS' THEN    ; Should we pop the stack ?
  1091.       &i: SETA &Nbr(&Result)        ; Maybe...see how &Result is specified
  1092.       IF (&i>0) AND (&UC(&Result[1]) = 'PASS') THEN ; Copy result -- do not pop!
  1093.         &Rslt:   SETC &Result[2]    ; 
  1094.         &A[2]:   SETC ''
  1095.         &i:      SETA &List(&Rslt, '&A', ':') ; Split the result
  1096.         &Rslt:   SETC &UC(&Trim(&A[1]))
  1097.         &RsltSz: SETC &Default(&UC(&Trim(&A[2])), &RsltSz)
  1098.         IF &Rslt = 'CC' THEN        ; Use result as condition code ?
  1099.           TST.&RsltSz (A7)
  1100.         ELSEIF &Rslt = 'POP' THEN    ; Simply pop the stack ?
  1101.           AERROR 'Cannot PASS and POP at the same time!'
  1102.         ELSE                    ; Copy stack into result
  1103.           MOVE.&RsltSz (A7),&A[1]
  1104.         ENDIF
  1105.       ELSE                    ; Pop result off the stack
  1106.         &A[2]:   SETC ''            
  1107.         &i:      SETA &List(&Rslt, '&A', ':') ; Split the result
  1108.         &Rslt:   SETC &UC(&Trim(&A[1]))
  1109.         &RsltSz: SETC &Default(&UC(&Trim(&A[2])), &RsltSz)
  1110.         IF &Rslt = 'CC' THEN        ; Use result as condition code ?
  1111.            TST.&RsltSz (A7)+
  1112.         ELSEIF &Rslt = 'POP' THEN    ; Simply pop the stack ?
  1113.          IF &RsltSz = 'L' THEN
  1114.           ADDQ.W    #4,A7
  1115.          ELSE
  1116.           ADDQ.W    #2,A7
  1117.          ENDIF
  1118.         ELSE                    ; Pop stack into result
  1119.           MOVE.&RsltSz (A7)+,&A[1]
  1120.         ENDIF
  1121.       ENDIF
  1122.     ENDIF
  1123. .*
  1124.         PRINT    Pop
  1125.         ENDM
  1126.  
  1127.         
  1128.         TITLE    'Dump file "ProgStrucMacs.d"'
  1129.         
  1130. ********************************************************************************
  1131.         DUMP        'ProgStrucMacs.d'
  1132. ********************************************************************************
  1133.         END        
  1134.